www.gusucode.com > VC 模范QQ做的一个界面-源码程序 > VC 模范QQ做的一个界面-源码程序/code/MyQQ/MagneticClass.cpp
//Download by http://www.NewXing.com // MagneticClass.cpp: implementation of the CMagneticClass class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "MyQQ.h" #include "MagneticClass.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CMagneticClass::CMagneticClass() : m_bLeftButtonDown(FALSE) , min_deltaX(800) , min_deltaY(600) , MagneticDistance(15) { InitializeCriticalSection(&m_cs); //初始化主窗口信息结构,由于主窗口只有一个,所以只需一个节点就够了 pMainWinInfo=new WinInfoStrt; //初始MovingWindow链表 pMovingWinChainHead=new WinInfoStrt; pMovingWinChainLast=pMovingWinChainHead; pMovingWinChainCur=pMovingWinChainHead; pMovingWinChainLast->nextPt=NULL; //初始化StandingWindow链表 pStandingWinChainHead=new WinInfoStrt; pStandingWinChainLast=pStandingWinChainHead; pStandingWinChainCur=pStandingWinChainHead; pStandingWinChainLast->nextPt=NULL; } CMagneticClass::~CMagneticClass() { } CMagneticClass::SetMainWinInfo(HWND hwnd) { RECT rc; GetWindowRect(hwnd,&rc); pMainWinInfo->hwnd = hwnd; pMainWinInfo->rc = rc; pMainWinInfo->nextPt = NULL; } //当一个子窗口初次显示,或由不可见的状态变为可见的状态时,需要调用此函数一次 //此函数将句柄为hwnd的窗口的信息作为一个新的节点添加到StandingWindowChain中 CMagneticClass::AddAChildWindowInfo(HWND hwnd) { RECT rc; GetWindowRect(hwnd, &rc); pStandingWinChainLast->nextPt = new WinInfoStrt; pStandingWinChainLast = pStandingWinChainLast->nextPt; pStandingWinChainLast->hwnd = hwnd; pStandingWinChainLast->rc = rc; pStandingWinChainLast->nextPt = NULL; } int CMagneticClass::DeleteAChildWindowInfo(HWND hwnd) { int DoneCode = DEL_FAILED; //先假设删除失败 WinInfoStrt *PrePtr, *CurPtr; //先在Moving window 链表中查找, 若找到则删除它并设置done标记为true; PrePtr = pMovingWinChainHead; CurPtr = pMovingWinChainHead->nextPt; while(CurPtr != NULL) { if(CurPtr->hwnd == hwnd) { PrePtr->nextPt = CurPtr->nextPt; delete CurPtr; DoneCode = DEL_IN_MOVING_CHAIN; // break; } else { PrePtr = CurPtr; CurPtr = CurPtr->nextPt; } } //如果被删除的是最后一个节点,则将指针pMovingWinChainLast //改指向前一个节点 if(CurPtr==pMovingWinChainLast) pMovingWinChainLast=PrePtr; //若在Moving window 链表中没找到,则继续在 Standing window 链表中查找 if(DoneCode != DEL_IN_MOVING_CHAIN) { PrePtr = pStandingWinChainHead; CurPtr = pStandingWinChainHead->nextPt; while(CurPtr != NULL) { if(CurPtr->hwnd == hwnd) { PrePtr->nextPt = CurPtr->nextPt; delete CurPtr; DoneCode = DEL_IN_STANDING_CHAIN; break; } else { PrePtr = CurPtr; CurPtr = CurPtr->nextPt; } } //如果被删除的是最后一个节点,则将指针pStandingWinChainLast //改指向前一个节点 if(CurPtr==pStandingWinChainLast) pStandingWinChainLast=PrePtr; } return DoneCode; } CMagneticClass::DeleteTheChain(CMagneticClass::WinInfoStrt* pchainHeadPtr) { WinInfoStrt *TempchainPt, *CurchainPt; CurchainPt = pchainHeadPtr->nextPt; while(CurchainPt != NULL) { TempchainPt= CurchainPt; CurchainPt = CurchainPt->nextPt; delete TempchainPt; } pchainHeadPtr->nextPt = NULL; } //此函数将源链表中的所有节点复制到目标链表中 CMagneticClass::CopyChain(/*HWND hwnd,*/ CMagneticClass::WinInfoStrt* SourceChainHead, CMagneticClass::WinInfoStrt* TargetChainLast) { WinInfoStrt* CurSourcePt = SourceChainHead->nextPt; while(CurSourcePt != NULL) { // if(CurSourcePt->hwnd != hwnd) // { TargetChainLast->nextPt = new WinInfoStrt; TargetChainLast = TargetChainLast->nextPt; *TargetChainLast = *CurSourcePt; // } CurSourcePt = CurSourcePt->nextPt; } TargetChainLast->nextPt = NULL; } CMagneticClass::CutPasteStuckChildWindow(CMagneticClass::WinInfoStrt *pCurMovingWinPtr) { WinInfoStrt *PrePtr, *CurPtr; PrePtr = pStandingWinChainHead; CurPtr = pStandingWinChainHead->nextPt; while(CurPtr != NULL) { /* if( abs(pCurMovingWinPtr->rc.bottom - CurPtr->rc.bottom)<MagneticDistance || abs(pCurMovingWinPtr->rc.bottom - CurPtr->rc.top)<MagneticDistance || abs(pCurMovingWinPtr->rc.top - CurPtr->rc.bottom)<MagneticDistance || abs(pCurMovingWinPtr->rc.top - CurPtr->rc.top)<MagneticDistance || abs(pCurMovingWinPtr->rc.left - CurPtr->rc.left)<MagneticDistance || abs(pCurMovingWinPtr->rc.left - CurPtr->rc.right)<MagneticDistance || abs(pCurMovingWinPtr->rc.right - CurPtr->rc.left)<MagneticDistance || abs(pCurMovingWinPtr->rc.right - CurPtr->rc.right)<MagneticDistance ) */ if( (pCurMovingWinPtr->rc.bottom == CurPtr->rc.bottom) || (pCurMovingWinPtr->rc.bottom == CurPtr->rc.top) || (pCurMovingWinPtr->rc.top == CurPtr->rc.bottom) || (pCurMovingWinPtr->rc.top == CurPtr->rc.top) || (pCurMovingWinPtr->rc.left == CurPtr->rc.left) || (pCurMovingWinPtr->rc.left == CurPtr->rc.right) || (pCurMovingWinPtr->rc.right == CurPtr->rc.left) || (pCurMovingWinPtr->rc.right == CurPtr->rc.right) ) { //剪切掉CurPtr指针所指向的节点 PrePtr->nextPt = CurPtr->nextPt; //然后,将这个被剪切下来的节点粘贴到MovingWindowChain的末尾 pMovingWinChainLast->nextPt=CurPtr; pMovingWinChainLast=CurPtr; pMovingWinChainLast->nextPt=NULL; //修改CurPtr指针的指向 CurPtr = PrePtr->nextPt; } else { PrePtr = CurPtr; CurPtr = CurPtr->nextPt; } } //如果pStandingWinChain已空, 及时修改链尾指针 if(pStandingWinChainHead->nextPt == NULL) { pStandingWinChainLast = pStandingWinChainHead; } } CMagneticClass::Add_StuckChildWindowsToMovingWindowChain() { //调用函数CutPasteStuckChildWindow,从pStandingWindowChainHead链中寻找跟主窗体粘在一起的子窗口 //若找到,就将其从StandingWindowChain中“剪切”掉,并“粘贴”到MovingWindowChain中的末尾 //剪切再粘贴是很好的技术,省掉了delete和new的操作 WinInfoStrt* currentPtr; currentPtr=pMovingWinChainHead->nextPt; //每次循环都用MovingWindowChain中的当前节点跟StandingWindowChain中的每个节点进行比对, //如果粘到了一起,就将StandingWindowChain中的节点剪切掉,粘贴到MovingWindowChain中的末尾 while(currentPtr!=NULL) { CutPasteStuckChildWindow(currentPtr); currentPtr=currentPtr->nextPt; } } CMagneticClass::FillingMovingAndStandingWindowChain(HWND hwnd) { UINT rt = DeleteAChildWindowInfo(hwnd); //将所有Moving window 中的节点复制到 Standing window 链表中, //以保证当前显示的所有窗口都被考虑到.一个当前显示的窗口不在Moving window中,必在Standing window中. CopyChain(pMovingWinChainHead, pStandingWinChainLast); //将 Moving window 链表清空 DeleteTheChain(pMovingWinChainHead); pMovingWinChainLast = pMovingWinChainHead; //若是主窗口,则 if(hwnd == pMainWinInfo->hwnd) { //把主窗口节点添加到 Moving window 链表中 pMovingWinChainLast->nextPt = new WinInfoStrt; pMovingWinChainLast = pMovingWinChainLast->nextPt; *pMovingWinChainLast = *pMainWinInfo; //寻找跟主窗口粘在一起的子窗口,也存入MovingWindowChain中 Add_StuckChildWindowsToMovingWindowChain(); } else //若拖动的是子窗口,则仅仅把这一个窗口添加到Moving window 链表中 { RECT rc; GetWindowRect(hwnd,&rc); pMovingWinChainLast->nextPt = new WinInfoStrt; pMovingWinChainLast = pMovingWinChainLast->nextPt; pMovingWinChainLast->nextPt = NULL; pMovingWinChainLast->hwnd =hwnd; pMovingWinChainLast->rc = rc; } } //此函数应该被放到OnLButtonDown消息处理函数中 CMagneticClass::OnLButtonDown_CriticalSession(HWND hwnd,POINT &point) { EnableWindow(hwnd,false); EnterCriticalSection(&m_cs); m_currentHwnd=hwnd;//保存被鼠标拖动的窗口的句柄到变量m_currentHwnd中,其实,这个值根本就没用,因为每个用来保存moving window的节点中都有窗口对应的句柄 m_bLeftButtonDown=TRUE; GetWindowRect(hwnd,&m_rcClient); m_MousePoint=point; SetCapture(hwnd); //重新获得主窗口和各个可见的子窗口的尺寸 ReGetTheSizeOfAllWindows(); //填充MovingWindowChain和StandingWindowChain这两个链表 FillingMovingAndStandingWindowChain(hwnd);//Save all Moving Windows into Moving Window Chain and Save All Standing Windows into Standing Window Chain LeaveCriticalSection(&m_cs); EnableWindow(hwnd,true); } CMagneticClass::OnLButtonUp_CriticalSession() { EnableWindow(m_currentHwnd,false); EnterCriticalSection(&m_cs); m_bLeftButtonDown=FALSE; ReleaseCapture(); LeaveCriticalSection(&m_cs); EnableWindow(m_currentHwnd,true); } CMagneticClass::OnMouseMove_CriticalSession(POINT &point) { if(m_bLeftButtonDown) { EnterCriticalSection(&m_cs); TRACE("PutThisFunctionInOnMouseMoveFunction\n"); min_deltaX=800; min_deltaY=600; //实现磁性移动的代码 //先求出鼠标移动的偏移量 offsetX=point.x-m_MousePoint.x; offsetY=point.y-m_MousePoint.y; //先要不考虑磁性作用,求出正常拖动窗体后,各个Moving window的新坐标 CalculateAllMovingWindowsNewPostion();//用类的private变量offsetX和offsetY来传递偏移量,所以,此函数不带参数 //求出各个Moving window被拖动后,X轴和Y轴方向的Moving windows与standing windows之间的最小距离。 Calculate_min_deltaX_and_min_deltaY();//计算deltaX和deltaY的值 // Calculate_DeltaX_and_DeltaY(); //如果距离值的绝对值大于有效的磁性距离,则无须再调整所有的Moving窗口的移动距离了。 //如果X方向的距离值的绝对值小于有效的磁性距离,则 if( (abs(min_deltaX)<MagneticDistance) && (min_deltaX!=0) ) { //修正X轴方向的偏移量 ModifyLeftAndRightCoordinatesOfAllMovingWindow(-min_deltaX); } //如果Y方向的距离值的绝对值小于有效的磁性距离,则 if( (abs(min_deltaY)<MagneticDistance) && (min_deltaY!=0) ) { //修正Y轴方向的偏移量 ModifyTopAndBottomCoordinatesOfAllMovingWindow(-min_deltaY); } Actually_Move_All_Moving_Windows(); LeaveCriticalSection(&m_cs); } } CMagneticClass::Actually_Move_All_Moving_Windows() { TRACE("Actually_Move_All_Moving_Windows\n"); WinInfoStrt* currentPtr; currentPtr=pMovingWinChainHead->nextPt; while(currentPtr!=NULL) { MoveWindow( currentPtr->hwnd, currentPtr->rc.left, currentPtr->rc.top, currentPtr->rc.right-currentPtr->rc.left, currentPtr->rc.bottom-currentPtr->rc.top, true ); /* SetWindowPos(currentPtr->hwnd, NULL, currentPtr->rc.left, currentPtr->rc.top, 0,0, SWP_NOSIZE); RedrawWindow(currentPtr->hwnd,NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); */ TRACE("MoveWindow\n"); currentPtr=currentPtr->nextPt; } } CMagneticClass::ReGetTheSizeOfAllWindows() { RECT rc; // WinInfoStrt* TempPtr; //获得主窗口尺寸 GetWindowRect(pMainWinInfo->hwnd, &rc); pMainWinInfo->rc = rc; pMovingWinChainCur = pMovingWinChainHead->nextPt; while(pMovingWinChainCur != NULL) { GetWindowRect(pMovingWinChainCur->hwnd, &rc); pMovingWinChainCur->rc = rc; pMovingWinChainCur = pMovingWinChainCur->nextPt; } pStandingWinChainCur = pStandingWinChainHead->nextPt; while(pStandingWinChainCur != NULL) { GetWindowRect(pStandingWinChainCur->hwnd, &rc); pStandingWinChainCur->rc = rc; pStandingWinChainCur = pStandingWinChainCur->nextPt; } } CMagneticClass::ModifyLeftAndRightCoordinatesOfAllMovingWindow(int deltaX) { WinInfoStrt* currentPtr; currentPtr=pMovingWinChainHead->nextPt; //需要先检验一下会不会把主窗口吸到屏幕里面出不来,如果不会的,才可以修改 if( (currentPtr->rc.left+deltaX < SCREENX)&& (currentPtr->rc.right+deltaX > 0) ) { while(currentPtr!=NULL) { currentPtr->rc.left +=deltaX; currentPtr->rc.right +=deltaX; currentPtr=currentPtr->nextPt; } } } CMagneticClass::ModifyTopAndBottomCoordinatesOfAllMovingWindow(int deltaY) { WinInfoStrt* currentPtr; currentPtr=pMovingWinChainHead->nextPt; //需要先检验一下会不会把主窗口吸到屏幕里面出不来,如果不会的,就修改 if( (currentPtr->rc.top+deltaY < SCREENY)&& (currentPtr->rc.bottom+deltaY > 0) ) { while(currentPtr!=NULL) { currentPtr->rc.top +=deltaY; currentPtr->rc.bottom +=deltaY; currentPtr=currentPtr->nextPt; } } } CMagneticClass::CalculateAllMovingWindowsNewPostion() { WinInfoStrt* currentPtr; currentPtr=pMovingWinChainHead->nextPt; while(currentPtr!=NULL) { currentPtr->rc.left +=offsetX; currentPtr->rc.right +=offsetX; currentPtr->rc.top +=offsetY; currentPtr->rc.bottom +=offsetY; currentPtr=currentPtr->nextPt; } } //实现磁性效应的最关键的一个函数!!! //要用两层嵌套的循环处理,外层循环是Moving Window,内层循环是Standing Window CMagneticClass::Calculate_min_deltaX_and_min_deltaY() { WinInfoStrt *currentPtr,*CurStandingPtr; int temp1; //先计算Y轴方向的距离,寻找最小的距离 currentPtr=pMovingWinChainHead->nextPt; while(currentPtr!=NULL) { CurStandingPtr=pStandingWinChainHead->nextPt; while(CurStandingPtr!=NULL) { //先计算Moving Window的横线 和 Standing Window的横线,是否进入了磁性效应的距离 //公式是:((x1L-D<x2L<x1R+D)||(x1L-D<x2R<x1R+D)) if( ( ((CurStandingPtr->rc.left-MagneticDistance)<currentPtr->rc.left)&& (currentPtr->rc.left<(CurStandingPtr->rc.right+MagneticDistance)) )|| ( ((CurStandingPtr->rc.left-MagneticDistance)<currentPtr->rc.right)&& (currentPtr->rc.right<(CurStandingPtr->rc.right+MagneticDistance)) ) ) { //计算公式是:|y2-y1|<D //top and top temp1=currentPtr->rc.top-CurStandingPtr->rc.top; if(abs(temp1)<MagneticDistance) { min_deltaY=temp1; } //top and bottom temp1=currentPtr->rc.top-CurStandingPtr->rc.bottom; if(abs(temp1)<MagneticDistance) { min_deltaY=temp1; } //bottom and top temp1=currentPtr->rc.bottom-CurStandingPtr->rc.top; if(abs(temp1)<MagneticDistance) { min_deltaY=temp1; } //bottom and bottom temp1=currentPtr->rc.bottom-CurStandingPtr->rc.bottom; if(abs(temp1)<MagneticDistance) { min_deltaY=temp1; } } CurStandingPtr=CurStandingPtr->nextPt; } currentPtr=currentPtr->nextPt; } //再计算X轴方向的距离,寻找最小的距离 currentPtr=pMovingWinChainHead->nextPt; while(currentPtr!=NULL) { CurStandingPtr=pStandingWinChainHead->nextPt; while(CurStandingPtr!=NULL) { //先计算Moving Window的横线 和 Standing Window的横线,是否进入了磁性效应的距离 //公式是:((y1Top-D<y2Top<y1Bottom+D)||(y1Top-D<y2Bottom<y1Bottom+D)) if( ( ((CurStandingPtr->rc.top-MagneticDistance)<currentPtr->rc.top)&& (currentPtr->rc.top<(CurStandingPtr->rc.bottom+MagneticDistance)) )|| ( ((CurStandingPtr->rc.top-MagneticDistance)<currentPtr->rc.bottom)&& (currentPtr->rc.bottom<(CurStandingPtr->rc.bottom+MagneticDistance)) ) ) { //计算公式是:|y2-y1|<D //left and left temp1=currentPtr->rc.left-CurStandingPtr->rc.left; if(abs(temp1)<MagneticDistance) { min_deltaX=temp1; } //left and right temp1=currentPtr->rc.left-CurStandingPtr->rc.right; if(abs(temp1)<MagneticDistance) { min_deltaX=temp1; } //right and left temp1=currentPtr->rc.right-CurStandingPtr->rc.left; if(abs(temp1)<MagneticDistance) { min_deltaX=temp1; } //right and right temp1=currentPtr->rc.right-CurStandingPtr->rc.right; if(abs(temp1)<MagneticDistance) { min_deltaX=temp1; } } CurStandingPtr=CurStandingPtr->nextPt; } currentPtr=currentPtr->nextPt; } } ///////////////////////////////////////////////////////////////////////// CMagneticClass MagneticObj; //全局变量,供其他窗口类引用实现磁性 void CMagneticClass::Calculate_DeltaX_and_DeltaY() { WinInfoStrt *currentPtr, *curStandingPtr; currentPtr = pMovingWinChainHead->nextPt; int dist = 65536; //计算X轴方向的距离 while(currentPtr != NULL) { curStandingPtr = pStandingWinChainHead->nextPt; while(curStandingPtr != NULL) { int TwoWidth = (currentPtr->rc.right - currentPtr->rc.left) + (curStandingPtr->rc.right - curStandingPtr->rc.left); int TwoHeight= (currentPtr->rc.bottom - currentPtr->rc.top) + (curStandingPtr->rc.bottom - curStandingPtr->rc.top); //left and right if((currentPtr->rc.right - curStandingPtr->rc.left < TwoWidth + MagneticDistance) && (currentPtr->rc.right > curStandingPtr->rc.right)) { dist = currentPtr->rc.left - curStandingPtr->rc.right; if(abs(dist) < MagneticDistance) { min_deltaX = dist; } } //right and left if((curStandingPtr->rc.right - currentPtr->rc.left < TwoWidth + MagneticDistance) && (curStandingPtr->rc.right > currentPtr->rc.right)) { dist = curStandingPtr->rc.left - currentPtr->rc.right; if(abs(dist) < MagneticDistance) { min_deltaX = dist; } } //top and bottom if((currentPtr->rc.bottom - curStandingPtr->rc.top < TwoHeight+MagneticDistance) && (currentPtr->rc.bottom > curStandingPtr->rc.bottom)) { dist = currentPtr->rc.top - curStandingPtr->rc.bottom; if(abs(dist) < MagneticDistance) { min_deltaY = dist; } } //bottom and top if((curStandingPtr->rc.bottom - currentPtr->rc.top < TwoHeight+MagneticDistance) && (curStandingPtr->rc.bottom > currentPtr->rc.bottom)) { dist = curStandingPtr->rc.top - currentPtr->rc.bottom; if(abs(dist) < MagneticDistance) { min_deltaY = dist; } } curStandingPtr = curStandingPtr->nextPt; } currentPtr = currentPtr->nextPt; } }